package com.thyme.content;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.thyme.content.dao.content.NoticeMapper;
import com.thyme.content.domain.dto.user.UserDTO;
import com.thyme.content.domain.entity.content.Notice;
import com.thyme.content.feignclient.CenterUserTestFeignClient;
import com.thyme.content.sentineltest.TestControllerBlockHandlerClass;
import com.thyme.content.sentineltest.TestControllerFallBackHandlerClass;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;

/**
 * @author thyme
 * @ClassName TestController
 * @Description TODO
 * @Date 2019/10/29 22:51
 */
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class TestController {

    private final NoticeMapper noticeMapper;

    private final DiscoveryClient discoveryClient;

    private final CenterUserTestFeignClient centerUserFeignClient;

    @RequestMapping("/test")
    public Notice testNotice(){
        Notice notice = new Notice();
        notice.setContent("xxxx");
        notice.setCreateTime(new Date());
        notice.setShowFlag(false);
        this.noticeMapper.insertSelective(notice);
        return notice;
    }

    @RequestMapping("/test2")
    public List<ServiceInstance> getInstances() {
         return this.discoveryClient.getInstances("center-user");
    }

    @RequestMapping("/test3")
    public UserDTO userDTO(UserDTO userDTO){
        return centerUserFeignClient.user(userDTO);
    }

    @RequestMapping("test_hot")
    @SentinelResource("hot")
    // 热点规则
    public String testHot(@RequestParam(required = false) String a,
                          @RequestParam(required = false) String b){
        return a+ ""+ b;
    }

    @GetMapping("/test-sentinel-api")
    public String testSentinelAPI(@RequestParam(required = false) String a){
        // 定义个sentinel保护的资源，名称是test-sentinel-api
        Entry entry = null;
        String resourceName = "test-sentinel-api";
        ContextUtil.enter(resourceName,"test-wfw");
        try {
            entry = SphU.entry(resourceName);
            // 被保护的业务逻辑
            if (StringUtils.isBlank(a)){
                throw new IllegalArgumentException("a is empty");
            }
            return a;
            // 如果被保护的资源被限流或者降级了，就会抛BlockException异常
        } catch (BlockException e) {
            log.warn("限流，或者降级了",e);
            return "限流，或者降级了";
        } catch (IllegalArgumentException e2){
            // 统计IllegalArgumentException 次数、占比等等
            Tracer.trace(e2);
            return "参数非法";
        } finally {
            if (entry != null){
                // 退出entry
                entry.exit();
            }
            ContextUtil.exit();
        }
    }

    @GetMapping("/test-sentinel-resource")
    @SentinelResource(value = "test-sentinel-api",
            blockHandler = "block",
            blockHandlerClass = TestControllerBlockHandlerClass.class,
            fallback = "fallback",
            fallbackClass = TestControllerFallBackHandlerClass.class
            )
    public String testSentinelResource(@RequestParam(required = false) String a){
        // 被保护的业务逻辑
        if (StringUtils.isBlank(a)){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            throw new IllegalArgumentException("a is empty");
        }
        return a;
    }

//    public String block(String a, BlockException e) {
//        log.warn("限流，或者降级了 block",e);
//        return "限流，或者降级 block";
//    }

//    public String fallback(String a) {
//        log.warn("限流，或者降级了 fallback");
//        return "限流，或者降级 fallback";
//    }

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test-sentinel-rest-templeate/{userId}")
    public UserDTO testSentinelRestTemplate(@PathVariable Integer userId){
        return this.restTemplate.getForObject("http://center-user/users/{userId}",
        UserDTO.class,userId);
    }
}
